﻿//*************************************************************************
//面向服务的协作式智能交通系统仿真软件SoC-ITSS v2.1 alpha
//发布单位：西北工业大学--巴黎高科MINES机器人与群智能系统联合实验室
//团队负责人：张凯龙 Zhang Kailong
//团队成员：张大方、杨安胜、王敏、谢策、王雨佳、谢尘玉等
//联系我们：kl.zhang@nwpu.edu.cn
//2012-2021
//*************************************************************************

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using CyberCarSimulation.Bean;
using CyberCarSimulation.RoadModel;
using CyberCarSimulation.Regulation;

//*******************************************************
//
//文件名(File Name):           Cloud.cs
//
//数据表(Tables):              nothing 
//
//          修改理由：         增加相应get set方法
//
//*******************************************************
namespace CyberCarSimulation.Cloud
{
    class TrafficCloudBPR
    {

        private string ID;                               //交通云
        private int StepMax = 30;                        //多久执行一次的全局动态调度
        private int Step = 0;                            //标记执行全局调度
        


        //Dijsktra算法使用
        static private int Row = MainData.CEIntersectionList.Count;
        private double[,] WeightMatrix = new double[Row, Row];                     //交通云存储道路网络权值，动态刷新
        private string[,] PathRoutingtable = new string[Row, Row];
        double[] distance = new double[Row];
        int[] prev = new int[Row];  
      


        //无参构造函数
        public TrafficCloudBPR(string ID, int NumberOfIntersection)
        {
            //初始化操作
            this.ID = ID;    
        }

        public void init()
        {
            ComputeLaneMaxLoad();
            ComputeLaneUnobstructedTime();
        }

        //计算车道的最大负载
        public void ComputeLaneMaxLoad()
        {
            //初始化车道的最大负载能力
            List<Lane> Centerlane = MainData.CenterLaneList;
            for (int i = 0; i < Centerlane.Count; i++) 
            {
                Lane LaneTemp = Centerlane[i];
                double MaxLoadTemp = (LaneTemp.GetLength() / 5) / (Definitions.Small_Length + Vehicle.FRONT_SAFE_DISTANCE);
                LaneTemp.SetMaxLoad(MaxLoadTemp);
            }
        }

        //计算每个车道无拥堵行驶时间
        public void ComputeLaneUnobstructedTime() 
        {
            //计算LaneUnobstructedTime
            //double Lanelength = MainData.CenterLaneList[0].GetLength()/5;
            //Lanelength-Coordinate.en

            //初始化车道的无拥堵行驶时间
            List<Lane> Centerlane = MainData.CenterLaneList;
            for (int i = 0; i < Centerlane.Count; i++)
            {
                Lane LaneTemp = Centerlane[i];    
                LaneTemp.SetUnobstructedTime(Coordinate.IntersationEnterTime);              
            }
        }



        //*********执行全局的调度算法入口（时间触发、时间触发）
        public void ExecuteGlobalAlgorithm() 
        {            
            //如果达到时间周期，执行更新道路权值、路径表
            if (this.Step == 0) 
            {
                RefreshWeightMatrix();
                DynamicDijsktra();
                this.Step = StepMax;
            }
            this.Step--;

            //读取处理车辆路径规划的消息
            HandleMessage();
        }

        //处理路径规划消息
        public void HandleMessage() 
        {
            //遍历存储的车辆发给交通云的消息 
            for (int i = 0; i < MainData.Map.V2CBuffer.Count; i++) 
            {
                V2CMessage V2CMessage = MainData.Map.V2CBuffer[i];             //拿到消息体
                int Type = V2CMessage.GetType();                               //消息类型
                string Sender = V2CMessage.GetSender();                        //发送方
                string StartIntersection = V2CMessage.GetStartIntersection();  //规划起始点
                string EndIntersection = V2CMessage.GetEndIntersection();      //终止点

                //根据消息类型按照不同方式处理
                if (Type == Definitions.MsgApply) 
                {
                    //构造反馈消息
                    C2VMessage C2VMessage = new C2VMessage(); //发送给车辆
                    C2VMessage.SetSender(this.ID);
                    C2VMessage.SetReceiver(Sender);  //发送方就是此消息接收方
                    C2VMessage.SetPathRoute(this.PathRoutingtable);
                    C2VMessage.SetType(Definitions.MsgFeedback);

                    //将消息写入队列
                    MainData.Map.C2VBuffer.Add(C2VMessage);
                }
            }

            //清空消息
            MainData.Map.V2CBuffer = new List<V2CMessage>();
        }
        
        //刷新全局道路网络权值
        public void RefreshWeightMatrix()
        {
            //设置车道权值
            List<Lane> Centerlane = MainData.CenterLaneList;
            for (int i = 0; i < Centerlane.Count; i++)
            {
                Lane LaneTemp = Centerlane[i];
                double WeightTemp = 1 + 0.15 * Math.Pow((LaneTemp.GetVehicleList().Count / LaneTemp.GetMaxLoad()), 4);
                WeightTemp *= LaneTemp.GetUnobstructedTime();
                LaneTemp.SetWeight(WeightTemp);  //道路权值
            }

            //设置道路权值
            List<Way> Centerway = MainData.CenterWayList;
            for (int i = 0; i < Centerway.Count; i++)
            {
                Way WayTemp = Centerway[i];
                double WeightTemp = 0;
                List<Lane> LaneTemp =  WayTemp.GetLaneList();

                //所有车道权值之和
                for (int j = 0; j < LaneTemp.Count; j++) 
                {
                    WeightTemp += LaneTemp[j].GetWeight();
                }

                WayTemp.SetWeight(WeightTemp / LaneTemp.Count); //对权值取均值
            }


            //抽取Way的权值到矩阵中
            string[,] RelationShip = MainData.Map.GetRelationShip();            
            double[,] RelationWeight = MainData.Map.GetRelationWeight();

            //遍历道路网络连通矩阵
            for (int i = 0; i < Row; i++) 
            {
                for (int j = 0; j < Row; j++) 
                {
                    if (RelationShip[i, j] != "0") 
                    {
                        RelationWeight[i,j] = MainData.FindWayByID(RelationShip[i, j]).GetWeight();
                    }
                }
            }

            //将数组复制到WeightMatrix
            for (int i = 0; i < Row; i++) 
            {
                for (int j = 0; j < Row; j++) 
                {
                    this.WeightMatrix[i, j] = RelationWeight[i, j];
                }
            }
                        
            
        }

        //动态Dijsktra计算最短路径 对外接口 调度之后 路径存储在PathRoutingtable中
        public void DynamicDijsktra() 
        {
            for (int i = 0; i < Row; i++)
            {
                FindWay(i);
                CreateWay(i);
            }           
        }

         /// <summary>
        /// Dijsktra算法的实现部分
        /// </summary>
        /// <param name="Start"></param>
        private void FindWay(int Start)
        {
            ArrayList S = new ArrayList(Row);//S储存确定最短路径的顶点的下标
            ArrayList U = new ArrayList(Row);//U中存储尚未确定路径的顶点的下标
            distance = new double[Row];         //存储start节点到其他节点的距离
            prev = new int[Row];


            //标记位
            List<bool> Isfor = new List<bool>();
            for (int temp = 0; temp < Row; temp++)
            {
                Isfor.Add(false);
            }

            S.Add(Start);//把源点加入集合S
            Isfor[Start] = true;//源点已经加入集合S

            //将除源点外的其他节点加入集合U
            for (int i = 0; i < Row; i++)
            {
                if (i != Start)
                    U.Add(i);
            }

            //把源点start到各个顶点的距离添加到distance中
            for (int i = 0; i < Row; i++)
            {
                distance[i] = WeightMatrix[Start, i];
                //prev[i] = 0;//将所有点的前一个点初始化为0
                prev[i] = Start;
            }

            int Count = U.Count;//集合U中元素的数量
            while (Count > 0)//当集合U中元素个数不为0
            {
                int min_index = (int)U[0];//假设U中第一个数存储的是最小的数的下标，min_index从1开始
                foreach (int r in U)//遍历集合U
                {
                    if (distance[r] < distance[min_index] && !Isfor[r])//如果源点到点r的距离小于到点min_index的，更新min_index
                        min_index = r;
                }
                S.Add(min_index);//S加入这个最近的点
                Isfor[min_index] = true;
                U.Remove(min_index);//U中移除这个点；

                foreach (int r in U)
                {
                    //查找下一行邻接矩阵，如何距离和上一个起点的距离和与数组存储的相比比较小，就更改新的距离和起始点,再比对新的起点到各边的距离
                    if (distance[r] > distance[min_index] + WeightMatrix[min_index, r])
                    {
                        distance[r] = distance[min_index] + WeightMatrix[min_index, r];
                        prev[r] = min_index;
                    }
                }
                Count = U.Count;//更新U中元素个数
            }

        }

        /// <summary>
        /// 生成具体的路径
        /// </summary>
        private void CreateWay(int Node)
        {
            for (int i = 0; i < Row; i++)
            {
                string Path = "" + Node;//记录到路由表最短路径

                int prePoint = prev[i];
                string s = "";
                StringBuilder sb = new StringBuilder(10);
                while (prePoint != Node)
                {
                    s = prePoint + s;
                    prePoint = prev[prePoint];
                }
                for (int j = 0; j < s.Length; j++)
                {
                    Path = Path + "-" + s[j];
                }

                Path = Path + "-" + i;
                PathRoutingtable[Node, i] = Path;
            }
        }



        //获取路由表
        //public static string[,] GetPathRouting()
        //{
        //    return PathRoutingtable;
        //}


        //获取step
        public int GetStep() 
        {
            return this.Step;
        }

        //设置完Step
        public void SetStep(int Step) 
        {
            this.Step = Step;
        }

        //设置道路权值
        public double[,] GetWeightMatrix() 
        {
            return this.WeightMatrix;
        }
             
    }
}
